//! # 认证模块全面测试套件
//!
//! 为认证模块的所有公共函数提供全面的单元测试

use crate::auth::*;
use axum::http::{HeaderMap, HeaderValue};
use std::collections::HashMap;
use std::time::{Duration, SystemTime};

#[cfg(test)]
mod auth_context_tests {
    use super::*;

    #[test]
    fn test_auth_context_new() {
        let headers = HeaderMap::new();
        let context = AuthContext::new(headers.clone(), "GET".to_string(), "/api/test".to_string(), Some("192.168.1.1".to_string()));
        assert_eq!(context.method, "GET");
        assert_eq!(context.uri, "/api/test");
        assert!(context.timestamp <= SystemTime::now());
    }

    #[test]
    fn test_auth_context_with_query_params() {
        let context = AuthContext::new(HeaderMap::new(), "GET".to_string(), "/api/test".to_string(), None);
        let mut params = HashMap::new();
        params.insert("key1".to_string(), "value1".to_string());
        let context_with_params = context.with_query_params(params.clone());
        assert_eq!(context_with_params.query_params, params);
    }

    #[test]
    fn test_auth_context_get_bearer_token() {
        let mut headers = HeaderMap::new();
        headers.insert("authorization", HeaderValue::from_static("Bearer token123"));
        let context = AuthContext::new(headers, "GET".to_string(), "/api/test".to_string(), None);
        assert_eq!(context.get_bearer_token(), Some("token123".to_string()));

        // 测试非Bearer格式
        let mut headers_basic = HeaderMap::new();
        headers_basic.insert("authorization", HeaderValue::from_static("Basic dXNlcjpwYXNz"));
        let context_basic = AuthContext::new(headers_basic, "GET".to_string(), "/api/test".to_string(), None);
        assert_eq!(context_basic.get_bearer_token(), None);
    }

    #[test]
    fn test_auth_context_get_api_key() {
        // 从Header获取
        let mut headers = HeaderMap::new();
        headers.insert("x-api-key", HeaderValue::from_static("sk_test_123"));
        let context = AuthContext::new(headers, "GET".to_string(), "/api/test".to_string(), None);
        assert_eq!(context.get_api_key(), Some("sk_test_123"));

        // 从查询参数获取
        let mut params = HashMap::new();
        params.insert("api_key".to_string(), "sk_query_456".to_string());
        let context_query = AuthContext::new(HeaderMap::new(), "GET".to_string(), "/api/test".to_string(), None)
            .with_query_params(params);
        assert_eq!(context_query.get_api_key(), Some("sk_query_456"));
    }
}

#[cfg(test)]
mod principal_tests {
    use super::*;

    #[test]
    fn test_principal_new() {
        let principal = Principal::new("user123".to_string(), "John Doe".to_string(), PrincipalType::User);
        assert_eq!(principal.id, "user123");
        assert_eq!(principal.name, "John Doe");
        assert_eq!(principal.principal_type, PrincipalType::User);
        assert!(principal.roles.is_empty());
        assert!(principal.permissions.is_empty());
    }

    #[test]
    fn test_principal_add_role() {
        let principal = Principal::new("user1".to_string(), "User One".to_string(), PrincipalType::User)
            .add_role("admin".to_string())
            .add_role("user".to_string());
        assert_eq!(principal.roles.len(), 2);
        assert!(principal.roles.contains(&"admin".to_string()));
        assert!(principal.roles.contains(&"user".to_string()));
    }

    #[test]
    fn test_principal_has_role() {
        let principal = Principal::new("user1".to_string(), "User One".to_string(), PrincipalType::User)
            .add_role("admin".to_string());
        assert!(principal.has_role("admin"));
        assert!(!principal.has_role("guest"));
    }

    #[test]
    fn test_principal_has_permission() {
        let principal = Principal::new("user1".to_string(), "User One".to_string(), PrincipalType::User)
            .add_permission("read:users".to_string());
        assert!(principal.has_permission("read:users"));
        assert!(!principal.has_permission("write:users"));
    }

    #[test]
    fn test_principal_is_expired() {
        // 未设置过期时间
        let principal_no_expiry = Principal::new("user1".to_string(), "User One".to_string(), PrincipalType::User);
        assert!(!principal_no_expiry.is_expired());

        // 未来时间
        let future_time = SystemTime::now() + Duration::from_secs(3600);
        let principal_future = Principal::new("user2".to_string(), "User Two".to_string(), PrincipalType::User)
            .with_expiry(future_time);
        assert!(!principal_future.is_expired());

        // 过去时间
        let past_time = SystemTime::now() - Duration::from_secs(3600);
        let principal_past = Principal::new("user3".to_string(), "User Three".to_string(), PrincipalType::User)
            .with_expiry(past_time);
        assert!(principal_past.is_expired());
    }

    #[test]
    fn test_principal_get_attribute() {
        let principal = Principal::new("user1".to_string(), "User One".to_string(), PrincipalType::User)
            .add_attribute("email".to_string(), "user@example.com".to_string());
        assert_eq!(principal.get_attribute("email"), Some(&"user@example.com".to_string()));
        assert_eq!(principal.get_attribute("phone"), None);
    }
}

#[cfg(test)]
mod resource_tests {
    use super::*;

    #[test]
    fn test_resource_new() {
        let resource = Resource::new("user-service".to_string(), "/api/users".to_string(), "GET".to_string());
        assert_eq!(resource.service, "user-service");
        assert_eq!(resource.path, "/api/users");
        assert_eq!(resource.method, "GET");
        assert!(resource.attributes.is_empty());
    }

    #[test]
    fn test_resource_get_resource_id() {
        let resource = Resource::new("user-service".to_string(), "/api/users/123".to_string(), "DELETE".to_string());
        assert_eq!(resource.get_resource_id(), "user-service:DELETE:/api/users/123");
    }

    #[test]
    fn test_resource_matches_method() {
        let resource = Resource::new("api".to_string(), "/test".to_string(), "GET".to_string());
        assert!(resource.matches_method("GET"));
        assert!(resource.matches_method("get")); // 大小写不敏感
        assert!(!resource.matches_method("POST"));
    }

    #[test]
    fn test_resource_matches_path() {
        let resource = Resource::new("api".to_string(), "/api/users".to_string(), "GET".to_string());
        assert!(resource.matches_path("/api/users"));
        assert!(!resource.matches_path("/api/posts"));
    }
}

#[cfg(test)]
mod auth_error_tests {
    use super::*;

    #[test]
    fn test_auth_error_variants() {
        let auth_failed = AuthError::AuthenticationFailed("Invalid credentials".to_string());
        let token_expired = AuthError::TokenExpired;
        
        assert!(auth_failed.to_string().contains("认证失败"));
        assert!(token_expired.to_string().contains("令牌已过期"));
    }

    #[test]
    fn test_auth_result() {
        let ok_result: AuthResult<String> = Ok("success".to_string());
        let err_result: AuthResult<String> = Err(AuthError::TokenExpired);
        
        assert!(ok_result.is_ok());
        assert!(err_result.is_err());
    }
}

#[cfg(test)]
mod permission_checker_tests {
    use super::*;

    #[test]
    fn test_permission_checker_basic() {
        let checker = BasicPermissionChecker::new();
        let principal = Principal::new("user1".to_string(), "User".to_string(), PrincipalType::User)
            .add_permission("read:users".to_string());

        assert!(checker.check_permission(&principal, "read:users"));
        assert!(!checker.check_permission(&principal, "write:users"));
    }

    #[test]
    fn test_permission_checker_wildcard() {
        let checker = BasicPermissionChecker::new();
        let principal = Principal::new("admin".to_string(), "Admin".to_string(), PrincipalType::Admin)
            .add_permission("*".to_string());

        assert!(checker.check_permission(&principal, "read:users"));
        assert!(checker.check_permission(&principal, "write:posts"));
    }
}

#[cfg(test)]
mod integration_tests {
    use super::*;

    #[test]
    fn test_complete_auth_flow() {
        let mut headers = HeaderMap::new();
        headers.insert("authorization", HeaderValue::from_static("Bearer token123"));
        
        let context = AuthContext::new(
            headers,
            "POST".to_string(),
            "/api/users".to_string(),
            Some("192.168.1.100".to_string()),
        );

        let principal = Principal::new("user123".to_string(), "Test User".to_string(), PrincipalType::User)
            .add_role("user".to_string())
            .add_permission("read:users".to_string());

        let resource = Resource::new("user-service".to_string(), "/api/users".to_string(), "POST".to_string());

        // 验证完整流程
        assert_eq!(context.get_bearer_token(), Some("token123".to_string()));
        assert!(principal.has_role("user"));
        assert!(resource.matches_method("POST"));
    }

    #[test]
    fn test_edge_cases() {
        // 空字符串测试
        let context = AuthContext::new(HeaderMap::new(), "".to_string(), "".to_string(), None);
        assert_eq!(context.method, "");
        assert_eq!(context.uri, "");

        // Unicode测试
        let unicode_principal = Principal::new("用户123".to_string(), "测试用户".to_string(), PrincipalType::User);
        assert_eq!(unicode_principal.id, "用户123");
    }
}